import Phaser from "phaser";

import { SpriteWithDynamicBody } from '../components/types';

const dinoThresholdY = 1.3888889;
const initSpeed      = 7;
export class PlayScene extends Phaser.Scene {

    private ground: Phaser.GameObjects.TileSprite;
    private dino: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody;
    private startTriggle: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody;

    private obstacles: Phaser.Physics.Arcade.Group;
    
    private gameOverText: Phaser.GameObjects.Image;
    private restart: Phaser.GameObjects.Image;
    private gameOverScreen: Phaser.GameObjects.Container;
    
    private isGameRunning: boolean;
    private respawnTime: number;
    
    private gameSpeed: number;

    private isFailed: boolean;
    private isInitialized: boolean;

    private score: number;
    private scoreText: Phaser.GameObjects.Text;
    private hightScoreText: Phaser.GameObjects.Text;

    private jumpSound: Phaser.Sound.BaseSound;
    private hitSound: Phaser.Sound.BaseSound;
    private reachSound: Phaser.Sound.BaseSound;
    

    constructor() {
        super('PlayScene');
        this.gameSpeed = initSpeed;
        this.respawnTime = 0;
    }

    create(): void {
        const {width, height} = this.game.config;
        
        this.isGameRunning = false, this.isFailed = false, this.isInitialized = true;
        this.score = 0;
        
        this.gameOverScreen = this.add.container(
            (width as number)/2, 
            (height as number)/3
        ).setAlpha(0)
        ;
        
        this.gameOverText = this.add.image(0, 0, 'game-over');
        this.restart = this.add.image(0, 70, 'restart').setInteractive().setScale(0.5);
        
        this.gameOverScreen.add([this.gameOverText, this.restart]);
        
        this.startTriggle = this.physics.add.sprite(0, 10, '')
            .setOrigin(0, 1)
            .setImmovable();
            ;
        
        this.ground = this.add
            .tileSprite(0, height as number, width as number, 26, 'ground')
            .setOrigin(0, 1)
            ;

        this.dino   = this.physics.add.sprite(1, height as number, 'dino-idle')
            .setGravityY(5000)
            .setCollideWorldBounds(true)
            .setOrigin(0, 1)
        ;
        
        this.obstacles = this.physics.add.group();


        // score
        this.scoreText = this.add.text(width as number, 0, '000000', {
            fontSize: '600 24px courier',
            color: '#535353',
            resolution: 5
        }).setOrigin(1, 0);


        this.hightScoreText = this.add.text(0, 0, 'HI 000000', {
            fontSize: '600 24px courier',
            color: '#535353',
            resolution: 5
        }).setOrigin(1, 0);

        this.hightScoreText.x = this.scoreText.x - this.scoreText.width - 20;
        
        this.jumpSound = this.sound.add('jump', {volume: 0.8});
        this.hitSound = this.sound.add('hit', {volume: 1});
        this.reachSound = this.sound.add('reach', {volume: 0.2});

        this.initAnimate();
        this.handleInputs();
        this.initStartTriggle();
        this.initColliders();
        this.handleScore();
    }

    pauseGame(){
        this.isGameRunning = false;
        this.physics.pause();
        this.anims.pauseAll();
        this.respawnTime = 0;
    }
    
    resumeGame(){
        this.isGameRunning = true;
        this.physics.resume();
        this.anims.resumeAll();
    }
    
    update(time: number, delta: number): void {
        if(!this.isGameRunning){
            return;
        }
        
        this.ground.tilePositionX += this.gameSpeed;
        this.respawnTime += delta * this.gameSpeed;
        if(this.respawnTime > 15000){
            this.placeObstacle();
            this.respawnTime = 0;
        }
        
        const obstaclesArray = this.obstacles.getChildren();
        Phaser.Actions.IncX(obstaclesArray, -this.gameSpeed);

        obstaclesArray.forEach((obstacle: SpriteWithDynamicBody) => {
            if (obstacle.getBounds().right < 0) {
                this.obstacles.remove(obstacle)
            }
        })
        
        // if(this.dino.y < (height as number)){
        let b = 0; 
        if((b = this.dino.body.deltaAbsY()) > dinoThresholdY && this.dino.body.height > 58){
            console.log('see this deltaAbsY b', b);
            this.dino.anims.stop();
            this.dino.setTexture('dino-run', 0);
        } else {
            // console.log('on ground');
            if(this.dino.body.height <= 58){
                this.dino.play('dino-down-anim', true);
            } else {
                this.dino.play('dino-run-anim', true);
            }
        }
    }
    
    handleInputs(){
        this.restart.on('pointerdown', () => {
            this.dino.setVelocity(0);
            this.dino.body.setSize(undefined, 92);
            this.dino.body.offset.y = 0;
            this.obstacles.clear(true, true);
            this.gameOverScreen.setAlpha(0);
            
            this.resumeGame();
            this.score = 0;
            this.gameSpeed = initSpeed;
            this.isFailed = false;
        });
        
        this.input.keyboard.on('keydown-SPACE', () => {
            if(!this.dino.body.onFloor()){
                return
            }
            
            this.dino.body.setSize(undefined, 92);
            this.dino.body.offset.y = 0;
            
            this.dino.setVelocity(-1600);
            this.jumpSound.play();
        });


        this.input.keyboard.on('keydown-DOWN', () => {
            console.log('key pressed down');
            this.dino.body.setSize(undefined, 58);
            this.dino.body.offset.y = 0;
        });


        this.input.keyboard.on('keyup-DOWN', () => {
            console.log('key released down');
            this.dino.body.setSize(undefined, 92);
            this.dino.body.offset.y = 0;
        });

        
        this.input.keyboard.on('keydown-P', () => {
            if(this.isFailed || this.isInitialized){ return; }
            
            if(this.isGameRunning){
                this.pauseGame();
            } else {
                this.resumeGame();
            }
        });
    }
    

    initColliders(){
        this.physics.add.collider(this.dino, this.obstacles, ()=>{
            this.pauseGame();
            
            const hiScore  = this.hightScoreText.text.split(' ')[1];
            const newScore = Number(this.scoreText.text) > Number(hiScore) ? this.scoreText.text : hiScore;

            this.hightScoreText.setText('HI ' + newScore);
            
            this.isFailed = true;
            this.gameOverScreen.setAlpha(1);
            this.dino.setTexture('dino-hurt');

            this.hitSound.play();
        });
    }
    

    initAnimate(){
        this.anims.create({
            key: 'dino-down-anim',
            frames: this.anims.generateFrameNames('dino-down'),
            frameRate: 10,
            repeat: -1
        });
        
        this.anims.create({
            key: 'dino-run-anim',
            frames: this.anims.generateFrameNames('dino-run'),
            frameRate: 10,
            repeat: -1
        });

        this.anims.create({
            key: 'enemy-bird-anim',
            frames: this.anims.generateFrameNames('enemy-bird'),
            frameRate: 10,
            repeat: -1
        });
    }
    
    
    placeObstacle(){
        const { width, height } = this.game.config;
        const obstaclesNum = Math.floor(Math.random() * 7) + 1;

        const distance = Phaser.Math.Between(600, 900);
        let obstacle;

        if(obstaclesNum > 6){
            const enemyHeight = [44, 66];
            obstacle = this.obstacles.create(
                // width as number + distance, 
                distance,
                height as number - enemyHeight[Math.floor(Math.random() * 2)], 
                'enemy-bird'
            )
            .setImmovable()
            .setOrigin(0, 1)
            ;

            obstacle.body.height = obstacle.body.height/1.5;
            obstacle.play('enemy-bird-anim', true);
        } else {
            obstacle = this.obstacles.create(
                // (width as number) + distance,
                distance,
                height as number, 
                `obstacle-${obstaclesNum}`
            )
            .setImmovable()
            .setOrigin(0, 1)
            ;
        }
    }
    
    initStartTriggle(){
        const { width, height } = this.game.config;
        this.physics.add.overlap(this.startTriggle, this.dino, ()=>{
            if(this.startTriggle.y === 10){
                this.isInitialized = false;
                this.startTriggle.body.reset(0, height as number);
                this.startTriggle.disableBody(true, true);

                const startEvent = this.time.addEvent({
                    delay: 16,
                    loop: true,
                    callbackScope: this,
                    callback: () => {
                        this.ground.setDisplaySize(this.ground.width+20, this.ground.displayHeight);
                        
                        if(this.ground.width >= (width as number)){
                            this.ground.setDisplaySize(width as number, this.ground.displayHeight);
                            this.isGameRunning = true;

                            startEvent.remove();
                        }
                    }
                });

                return;
            }
        });
    }

    handleScore(){
        this.time.addEvent({
           delay: 100,
           loop: true,
           callbackScope: this,
           callback: () => {
                if(!this.isGameRunning){ return; }
                
                this.score += 2;
                this.gameSpeed += 0.01;
                
                if((this.score % 100) === 0){
                    this.reachSound.play();
                    this.tweens.add({
                        targets: this.scoreText,
                        duration: 100,
                        repeat: 3,
                        props: {
                            alpha: 0,
                        },
                        yoyo: true
                    });
                }

                const socreTmp = Array.from(String(this.score), Number);
                // console.log('see scoreTmp', socreTmp);
                for(let i=0; i<6-String(this.score).length; i++){
                    socreTmp.unshift(0);
                }
                this.scoreText.setText(socreTmp.join(''));
           }
        });
    }
}